#include "process.h"

int exit_flag = 0;
int must_run_size;
struct proc_struct must_run_proc[SIZE];
/*
 * @file      process.c
 * @function  run_moniter
 * @author    酸菜。
 * @date      2021-05-10
*/
void run_moniter(char *Filename)
{
    /*从配置文件当中读取配置信息，存入到must_run_proc
    结构体数组当中，返回值为要监控的进程个数，其中每个
    进程包括了进程ID以及进程名*/
    must_run_size = get_proc(Filename, "aa", must_run_proc, SIZE);
    /*小于0说明没有要监控的进程*/
    if(must_run_size <= 0) {
        return;
    }
#if 0
    /*注册信号处理函数,用来闭守护进程*/
    if(signal(SIGINT, exit_proc) == SIG_ERR) {
        printf("无法捕捉SIGUSR1信号!\n");
    }
#endif
    /*检测并启动未启动的进程*/
    while(1) {
        moniter_run(must_run_proc, must_run_size);
        sleep(2);
    }
    return;
}
/*
 * @file      main.c
 * @function  creat_daemon
 * @author    酸菜。
 * @date      2021-05-10
*/
int creat_daemon()
{
    int  fd;
    /*创建子进程*/
    switch (fork()) {
    case -1:
        /*创建子进程失败，这里可以写日志*/
        return -1;
    case 0:
        /*子进程，走到这里，直接break*/
        break;
    default:
        /*父进程(没有用了)，直接退出*/
        exit(0);
    }
    /*只有子进程流程才能走到这里脱离终端，
    终端关闭，将跟此子进程无关，设置子进程
    成为一个守护进程*/
    if (setsid() == -1) {
        /*记录错误日志*/
        return -1;
    }
    /*设置为0，不要让它来限制文件权限，以免引起混乱*/
    umask(0);
    /*切换到根目录*/
   // if(child("/") < 0) {
        /*记录错误日志*/
        return -1;
    }
    /*打开黑洞设备，以读写方式打开*/
    fd = open("/dev/null", O_RDWR);
    if (fd == -1) {
        /*记录错误日志*/
        return -1;
    }
    /*让STDIN_FILENO，STDOUT_FILENO
    与fd共享一个文件表项，即它们都指向黑洞*/

    /*先关闭STDIN_FILENO[这是规矩，
    已经打开的描述符，动他之前，先close，
    类似于指针指向null，让/dev/null成为标准输入；*/
    if (dup2(fd, STDIN_FILENO) == -1) {
        /*记录错误日志*/
        return -1;
    }
    /*先关闭STDIN_FILENO，类似于指针指向null，让/dev/null成为标准输出*/
    if (dup2(fd, STDOUT_FILENO) == -1) {
        /*记录错误日志*/
        return -1;
    }
    /*fd应该是3，这个应该成立*/
    if (fd > STDERR_FILENO) {
        /*释放资源这样这个文件描述符就可以被复用；不然这个文件描述会被一直占着*/
        if (close(fd) == -1)/*fd这个文件描述符已经不用了*/{
            /*记录错误日志*/
            return -1;
        }
    }
    return 1;
}
/*
 * @file      process.c
 * @function  
 * @author    酸菜。
 * @date      2021-05-10
*/
int proc_find(struct proc_struct* src, struct proc_struct* dest)
{
    char buffer[4096], *p, cmd[20];
    int fd, len;

    /*字符串拼接*/
    sprintf(buffer, "%d/stat", src->pid);
    fd = open(buffer, O_RDONLY);
    if(fd == -1) {
        return 0;
    }
    memset(buffer, '\0', sizeof(buffer));
    len = read(fd, buffer, sizeof(buffer) - 1);
    close(fd);
    if(len <= 0) {
        return 0;
    }
    p = buffer;
    p = strrchr(p, '(');

    {
        char *q = strrchr(p, ')');
        /*进程名称的长度*/
        int len = q - p - 1;
        /*应该不会超过128*/
        if (len >= sizeof(src->process_name))
        {
            len = sizeof(src->process_name) - 1;
        }
        /*把从proc目录下读到的进程名称写入src->process_name*/
        memcpy(src->process_name, p+1, len);
        /*最后一位记得补'\0'*/
        src->process_name[len]= 0;
        /*现在p指向'('的后一位字符*/
        p = q + 1;
    }
    /*两个进程名称进行比较,相等则说明该进程正在运行*/
    return (strcmp(src->process_name, dest->process_name) == 0) ? 1 :0;
}
/*
 * @file      process.c
 * @function  check_proc
 * @author    酸菜。
 * @date      2021-05-10
*/
int check_proc(struct proc_struct* array)
{
    DIR  *dp;
    char *dir = PROCES;
    struct dirent *dirp;
    struct proc_struct* proc;
    struct proc_struct* tmp;

    /*array为空则直接返回*/
    if(array == NULL) {
        return 0;
    }

    /*切换到/proc路径*/
    chdir(dir);

    /*读取/proc目录下所有文件夹和文件的信息，
    dp保存所有这些读取到的信息，如果dir是一个
    文件，则直接返回NULL*/
    if((dp = opendir(dir)) == NULL) {
        return 0;
    }
    /*循环读取dp读到的信息*/
    while ((dirp = readdir(dp)) != NULL) {
        char data[30];
        /*dirp->d_process_name文件夹名称，即进程ID
        保存到data里*/
        sprintf(data, "%s", dirp->d_name);

        /*判断data的内容是否是纯数字*/
        if((strspn(data, "0123456789") == strlen(data))) {
            proc = (struct proc_struct *)(malloc(sizeof(struct proc_struct)));
            tmp = proc;
            proc->pid = atoi(dirp->d_name);
            /*判断配置文件里的进程是否在运行*/
            if(proc_find(proc, array)) {
                printf("进程正在运行!\n");
                return 1;
            }
            free(tmp);
        }
    }
    /*关闭该目录*/
    closedir(dp);
    return 0;
}
/*
 * @file      process.c
 * @function  get_proc
 * @author    酸菜。
 * @date      2021-05-10
*/
int get_proc(unsigned char *pu1Filename, unsigned char *pu1SearchStr, struct proc_struct* array, int size)
{
    FILE            *pFile;
    static   int     nRet = 0;
    unsigned char    au1Buf[80];
    unsigned char    au1ReadStr[80];
    unsigned char    au1StrValue[80];
    unsigned char    au1TmpValue[80];
    unsigned char    *pu1Temp;

    pFile = fopen ((const char*)pu1Filename, "r");

    if ((pFile == NULL) || (size <= 0) || (array == NULL)) {
        return 0;
    }

    memset(au1Buf, 0, 80);

    while ((!feof (pFile)) && nRet < size) {
        fgets (au1Buf, 80, pFile);
        if ((strstr (au1Buf, pu1SearchStr)) != NULL) {
            memset (au1ReadStr, 0, 80);
            memset (au1StrValue, 0, 80);
            memset (au1TmpValue, 0, 80);
            sscanf(au1Buf, "%s%s%s", au1ReadStr, au1StrValue, au1TmpValue);
            /*一行一行读取，不是要读取的字符串就直接下一个*/
            if (strcmp (au1ReadStr, pu1SearchStr) != 0) {
                continue;
            }
            /*将读取到的value保存到结构体数组当中*/
            if(strlen (au1TmpValue) != 0) {
                strcpy (&array->process_name[nRet], au1TmpValue);
            }
            else {
                pu1Temp = au1StrValue;
                pu1Temp++;
                strcpy(&array->process_name[nRet], pu1Temp);
            }
            nRet++;
            break;
        }
    }
    fclose (pFile);
    return nRet;
}
/*
 * @file      process.c
 * @function  startProc
 * @author    酸菜。
 * @date      2021-05-10
*/
int startProc(struct proc_struct* proc, int must_run_size)
{
    if(proc == NULL) {
        return 0;
    }

    int pid = fork();

    if(pid == 0) {
        pid = fork();
        if(pid == 0) {
            execl("/home/txj/test1", (char *)proc->process_name, NULL);
        }
        else {
            exit(0);
        }
        sleep(2);
    }
    else {
        /*不用关心子进程的退出状态，这里为了
        避免子进程成为僵死进程直接使用NULL即可*/
        wait(NULL);
        sleep(1);
    }
    return 0;
}
/*
 * @file      process.c
 * @function  moniter_run
 * @author    酸菜。
 * @date      2021-05-10
*/
int moniter_run(struct proc_struct *must_run_proc, int proc_size)
{
    int i4Index = 0;
    for(i4Index = 0; i4Index < must_run_size; i4Index++) {
        if(check_proc(&(must_run_proc[i4Index])) <= 0) {
            startProc(&(must_run_proc[i4Index]), proc_size);
        }
    }
    return 1;
}
/*
 * @file      process.c
 * @function  exit_proc
 * @author    酸菜。
 * @date      2021-05-10
*/
void exit_proc(int sig)
{
    (void)sig;
    kill(getpid(), SIGTERM); 
    exit(0);
}
